#include "vgdb.h"

/* 返回值:
 * -5
 * -4
 * -3
 * -2 : 缓冲区满
 * -1 : read出错
 *  0 : socket关闭
 *  1 : 一切正常, 读到的数据:'\n'->'\0'
 *  参数len返回读到的实际数据, 若一切正常, 将为正常数据的长度(\n->\0)
 *  若是发生异常, len返回异常之前成功读取到的数据
 */
int sockgetmsg(int sock, char *buff, int blen, int *len)
{
    int     ret_len;

    if(!buff){
        return -5;
    }
    if(!len){
        return -4;
    }
    if(blen <= 0){
        return -3;
    }

    ret_len = 0;
    while(ret_len<blen){
        switch(recv(sock, (void*)(buff+ret_len), 1, 0)){
            case 1:
                if((*(buff+ret_len) == '\n') || (*(buff+ret_len) == '\0')){
                    *(buff+ret_len) = '\0';
                    *len = ret_len;
                    return 1;
                }else{
                    ret_len++;
                }
                break;
            case 0:
                *len = ret_len;
                return 0;
            default:
                *len = ret_len;
                return -1;
        }
    }
    *len = ret_len;
    return -2;
}


vmsg_t *vmsg_parse(vmsg_t *dst, const char *vmstr)
{

    char        tmp[512];
    char       *ptr;
    int         p;

    DEBUG_MESSAGE("vim message : %s\n", vmstr);
    strcpy(tmp, vmstr);
    ptr = tmp;
    p = strspn(ptr, "0123456789");
    if(p == 0){
        //special
        p = strspn(ptr, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        ptr[p] = 0;
        dst->vmid = vmsg_vmid(ptr, VGDB_VMT_S);
        return dst;
    }else{

        if(tmp[p] != ':'){
            // reply
            if(tmp[p] == ' '){
                dst->vmid = 0;
                ptr[p] = 0;
                sscanf(ptr, "%d", &(dst->seqno));
                strcpy(dst->args, ptr+p+1);
            }else{
                // '\0' 没有参数的回复
                dst->vmid = 0;
                sscanf(ptr, "%d", &(dst->seqno));
            }

        }else{
            // ':' any other
            ptr[p] = 0;
            sscanf(ptr, "%d", &(dst->bid));

            ptr += p+1;
            p = strcspn(ptr, "!=/");
            ptr[p] = 0;
            dst->vmid = vmsg_vmid(ptr, VGDB_VMT_E);

            ptr += p+1;
            p = strspn(ptr, "0123456789");
            if(ptr[p] == 0){
                // no arguments
                sscanf(ptr, "%d", &(dst->seqno));
            }else{
                ptr[p] = 0;
                sscanf(ptr, "%d", &(dst->seqno));
                ptr += p+1;
                strcpy(dst->args, ptr);
            }
        }
        return dst;
    }
}



void vmsg_proc()
{
    int     len;
    vmsg_t  vmsg;
    switch(sockgetmsg(vim()->datsock, vim()->msgb, vim()->blen, &len)){
        case -5:
        case -4:
        case -3:
        case -2:
        case -1:
            DEBUG_MESSAGE("sockgetmsg() falil: unknown error\n");
            break;
        case  0:
            DEBUG_MESSAGE("sockgetmsg() falil: vim socket closed\n");
            break;
        default:
            vmsg_parse(&vmsg, vim()->msgb);
            vmsg_exec(&vmsg);
            break;
    }
}


/* 返回 [start, end]
 * 将[0, start-1]保留不用
**/

int vmsg_hash(const char* str, int start, int end, int mod)
{
    unsigned int  p, ret;
    unsigned int  key;
    unsigned char ch;

    if((start < 0) || (end < 0) || (start>end)){
        return end+1;
    }else{
        ret = 0;
        p   = 0;
        key = 77;
        while(str[p]){
            ch  = str[p]-'a';
            //ret += (ret<<(ch%sizeof(ret))^ch*(key<<p%sizeof(key))+ch*key*p);
            ret += ch*mod;
            p++;
        }
        return ret%(end-start+1) + start;
    }
}







void vmsg_init()
{
    vmsg_func(0                                      ) = vmsgr_reply;
    vmsg_func(vmsg_vmid("balloonEval"   , VGDB_VMT_E)) = vmsge_ballooneval;
    vmsg_func(vmsg_vmid("balloonText"   , VGDB_VMT_E)) = vmsge_balloontext;
    vmsg_func(vmsg_vmid("buttonRelease" , VGDB_VMT_E)) = vmsge_buttonrelease;
    vmsg_func(vmsg_vmid("disconnect"    , VGDB_VMT_E)) = vmsge_disconnect;
    vmsg_func(vmsg_vmid("fileClosed"    , VGDB_VMT_E)) = vmsge_fileclosed;
    vmsg_func(vmsg_vmid("fileModified"  , VGDB_VMT_E)) = vmsge_filemodified;
    vmsg_func(vmsg_vmid("fileOpened"    , VGDB_VMT_E)) = vmsge_fileopened;
    vmsg_func(vmsg_vmid("geometry"      , VGDB_VMT_E)) = vmsge_geometry;
    vmsg_func(vmsg_vmid("insert"        , VGDB_VMT_E)) = vmsge_insert;
    vmsg_func(vmsg_vmid("invokeAction"  , VGDB_VMT_E)) = vmsge_invokeaction;
    vmsg_func(vmsg_vmid("keyCommand"    , VGDB_VMT_E)) = vmsge_keycommand;
    vmsg_func(vmsg_vmid("keyAtPos"      , VGDB_VMT_E)) = vmsge_keyatpos;
    vmsg_func(vmsg_vmid("killed"        , VGDB_VMT_E)) = vmsge_killed;
    vmsg_func(vmsg_vmid("newDotAndMark" , VGDB_VMT_E)) = vmsge_newdotandmark;
    vmsg_func(vmsg_vmid("quit"          , VGDB_VMT_E)) = vmsge_quit;
    vmsg_func(vmsg_vmid("remove"        , VGDB_VMT_E)) = vmsge_remove;
    vmsg_func(vmsg_vmid("revert"        , VGDB_VMT_E)) = vmsge_revert;
    vmsg_func(vmsg_vmid("save"          , VGDB_VMT_E)) = vmsge_save;
    vmsg_func(vmsg_vmid("startupDone"   , VGDB_VMT_E)) = vmsge_startupdone;
    vmsg_func(vmsg_vmid("unmodified"    , VGDB_VMT_E)) = vmsge_unmodified;
    vmsg_func(vmsg_vmid("version"       , VGDB_VMT_E)) = vmsge_version;
    vmsg_func(vmsg_vmid("ACCEPT"        , VGDB_VMT_S)) = vmsgs_accept;
    vmsg_func(vmsg_vmid("AUTH"          , VGDB_VMT_S)) = vmsgs_auth;
    vmsg_func(vmsg_vmid("DISCONNECT"    , VGDB_VMT_S)) = vmsgs_disconnect;
    vmsg_func(vmsg_vmid("DETACH"        , VGDB_VMT_S)) = vmsgs_detach;
    vmsg_func(vmsg_vmid("REJECT"        , VGDB_VMT_S)) = vmsgs_reject;

    vcmd_init();
}









void vmsgr_reply (vmsg_t *vmsg)
{
}
void vmsge_ballooneval (vmsg_t *vmsg)
{
}
void vmsge_balloontext (vmsg_t *vmsg)
{
}
void vmsge_buttonrelease (vmsg_t *vmsg)
{
}
void vmsge_disconnect (vmsg_t *vmsg)
{
    /* vim退出 */
    close(vim()->datsock);
    vim()->state = VGDB_VS_QUIT;
    gdb_exec("quit\n");
    close(gdb()->rwfd);
    waitpid(gdb()->pid, NULL, 0);
    gdb()->state = VGDB_GS_QUIT;

    vgdb()->state = VGDB_VS_QUIT;
}
void vmsge_fileclosed (vmsg_t *vmsg)
{
}
void vmsge_filemodified (vmsg_t *vmsg)
{
}
void vmsge_fileopened (vmsg_t *vmsg)
{
}
void vmsge_geometry (vmsg_t *vmsg)
{
}
void vmsge_insert (vmsg_t *vmsg)
{
}
void vmsge_invokeaction (vmsg_t *vmsg)
{
}
void vmsge_keycommand (vmsg_t *vmsg)
{
    vcmd_t  vcmd;
    char   *ptr;
    char    buff[256];
    ptr = strchr(vmsg->args,'"') + 1;
   *strchr(ptr, '"') = 0;
    strcpy(buff, ptr);

    ptr = strchr(buff, ' ');
    if(ptr){
        *ptr = 0;
        vcmd.vcid = vcmd_vcid(buff);
        strcpy(vcmd.args, ptr+1);
    }else{
        vcmd.vcid = vcmd_vcid(buff);
        strcpy(vcmd.args, "");
    }
    vcmd_exec(&vcmd);
}
void vmsge_keyatpos (vmsg_t *vmsg)
{
}
void vmsge_killed (vmsg_t *vmsg)
{
}
void vmsge_newdotandmark (vmsg_t *vmsg)
{
}
void vmsge_quit (vmsg_t *vmsg)
{
}
void vmsge_remove (vmsg_t *vmsg)
{
}
void vmsge_revert (vmsg_t *vmsg)
{
}
void vmsge_save (vmsg_t *vmsg)
{
}


void vmsge_startupdone(vmsg_t *vmsgstr)
{
    char    buff[512];

    vim()->state = VGDB_VS_ATTACHED;

    sprintf(buff, "file %s\n", gdb()->symfn);
    gdb_exec(buff);

    gdb_exec("list\n");

    gdb_exec("info source\n");
    strcpy(vim()->curfn, gdb_opln(3)+11);
    
    gdb_exec("break main\n");
    sscanf(strstr(gdb_opln(gdb()->bcur),", line ")+7,"%d", &(vim()->curln));

    gdb_exec("clear main\n");

    vmsg_send("0:setExitDelay!%d 0\n", vim()->seqno);
    vmsg_send("%d:editFile!%d \"%s\"\n", VGDB_BID_SOURCE, vim()->seqno, vim()->curfn);
    vmsg_send("%d:startDocumentListen!%d\n", VGDB_BID_SOURCE, vim()->seqno);
    vmsg_send("%d:setDot!%d %d/%d\n", VGDB_BID_SOURCE, vim()->seqno, vim()->curln, vim()->curofs);

    vim()->state = VGDB_VS_STOP;
}

void vmsge_unmodified (vmsg_t *vmsg)
{
}

void vmsge_version(vmsg_t *vmsg)
{
    vim()->version = 205;
}

void vmsgs_accept (vmsg_t *vmsg)
{
}
void vmsgs_auth (vmsg_t *vmsg)
{
}
void vmsgs_disconnect (vmsg_t *vmsg)
{
}
void vmsgs_detach (vmsg_t *vmsg)
{
}
void vmsgs_reject (vmsg_t *vmsg)
{
}
